#include "stdafx.h"
#include "ZAcceptor.h"
#include "ZSocket.h"
#include "ZAsyncSocket.h"
#include "ZSocketNetworkController.h"
#include "ZUtility.h"
#include <assert.h>

namespace	Z	{

//------------------------------------------------------------------------------------------------------------------------
Acceptor::Acceptor(SocketNetworkController* pSocketNetworkController, u_short port)
:	mSocketNetworkController(pSocketNetworkController),
	mSocket(new Socket(INVALID_SOCKET)),
	mAccept(0),
	mProcess(0),
	mPort(port)
{
}

Acceptor::~Acceptor()
{
}

bool Acceptor::start()
{
	if(!create())
		return false;
	if(!bind(mPort))
		return false;
	if(!selectEvent())
		return false;
	if(!startProcess())
		return false;
	if(!listen())
		return false;

	return true;
}

void Acceptor::accept()
{
	SOCKADDR_IN addr;
	zeroise(addr);
	int addrlen	= sizeof(addr);
	SOCKET so	= ::WSAAccept(mSocket->getHandle(), (SOCKADDR *)&addr, &addrlen, 0, 0); 

	if(so == INVALID_SOCKET)
		return;

	static	NetworkId	sNetworkId	= SocketNetworkController::initialNetworkId;
	AsyncSocket* pSocket	= new AsyncSocket(so, sNetworkId++);
	if(!mSocketNetworkController->postCompletionStatus(SocketNetworkController::create, 0, reinterpret_cast<OVERLAPPED*>(pSocket)))	{
		deletePtr(pSocket);
	}
}

void Acceptor::process()
{
	HANDLE handles[]	=	{	mProcess, mAccept	};
	while(true)	{
		DWORD result	= ::WaitForMultipleObjects(2, handles, FALSE, INFINITE);
		if(result == WAIT_OBJECT_0)
			return;

		WSANETWORKEVENTS ne;
		::WSAEnumNetworkEvents(mSocket->getHandle(), mAccept, &ne);
		if(ne.lNetworkEvents == FD_ACCEPT)	{
			accept();
		}
	}
}

bool Acceptor::create()
{
	assert(mSocket->getHandle() == INVALID_SOCKET);
	assert(!mProcessThread.joinable());

	return mSocket->create(AF_INET, SOCK_STREAM, IPPROTO_TCP, WSA_FLAG_OVERLAPPED);
}

void Acceptor::destroy()
{
	if(mProcessThread.joinable())	{
		::SetEvent(mProcess);
		mProcessThread.join();
		closeEvent(mProcess);
	}
	closeEvent(mAccept);
	mSocket->close();
}

bool Acceptor::bind(u_short port)
{
	assert(mSocket->getHandle() != INVALID_SOCKET);

	SOCKADDR_IN sin;
	sin.sin_family	= PF_INET;
	sin.sin_addr.s_addr	= ::htonl(INADDR_ANY);
	sin.sin_port	= ::htons(port);
	return ::bind(mSocket->getHandle(), (LPSOCKADDR)&sin, sizeof(sin)) != SOCKET_ERROR;
}

bool Acceptor::listen()
{
	return ::listen(mSocket->getHandle(),SOMAXCONN) != SOCKET_ERROR;
}

bool Acceptor::selectEvent()
{
	mAccept	= ::WSACreateEvent();
	if(mAccept == WSA_INVALID_EVENT)
		return false;
	return ::WSAEventSelect(mSocket->getHandle(), mAccept, FD_ACCEPT | FD_CONNECT ) != SOCKET_ERROR;
}

bool	Acceptor::startProcess()
{
	mProcess	= ::WSACreateEvent();
	mProcessThread	= boost::thread(boost::bind(&Acceptor::process, this));
	return mProcessThread.joinable();
}

}